// Copyright 2016 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#ifndef CORE_FPDFAPI_PARSER_CPDF_STREAM_H_
#define CORE_FPDFAPI_PARSER_CPDF_STREAM_H_

#include <stdint.h>

#include <memory>
#include <set>

#include "core/fpdfapi/parser/cpdf_object.h"
#include "core/fxcrt/data_vector.h"
#include "core/fxcrt/fx_string_wrappers.h"
#include "core/fxcrt/retain_ptr.h"
#include "third_party/abseil-cpp/absl/types/variant.h"

class IFX_SeekableReadStream;

class CPDF_Stream final : public CPDF_Object {
 public:
  static constexpr int kFileBufSize = 512;

  CONSTRUCT_VIA_MAKE_RETAIN;

  // CPDF_Object:
  Type GetType() const override;
  RetainPtr<CPDF_Object> Clone() const override;
  WideString GetUnicodeText() const override;
  CPDF_Stream* AsMutableStream() override;
  bool WriteTo(IFX_ArchiveStream* archive,
               const CPDF_Encryptor* encryptor) const override;

  size_t GetRawSize() const;
  // Can only be called when stream is memory-based.
  // This is meant to be used by CPDF_StreamAcc only.
  // Other callers should use CPDF_StreamAcc to access data in all cases.
  pdfium::span<const uint8_t> GetInMemoryRawData() const;

  // Copies span or stream into internally-owned buffer.
  void SetData(pdfium::span<const uint8_t> pData);
  void SetDataFromStringstream(fxcrt::ostringstream* stream);

  void TakeData(DataVector<uint8_t> data);

  // Set data and remove "Filter" and "DecodeParms" fields from stream
  // dictionary. Copies span or stream into internally-owned buffer.
  void SetDataAndRemoveFilter(pdfium::span<const uint8_t> pData);
  void SetDataFromStringstreamAndRemoveFilter(fxcrt::ostringstream* stream);

  void InitStreamFromFile(RetainPtr<IFX_SeekableReadStream> file);

  // Can only be called when a stream is not memory-based.
  DataVector<uint8_t> ReadAllRawData() const;

  bool IsFileBased() const {
    return absl::holds_alternative<RetainPtr<IFX_SeekableReadStream>>(data_);
  }
  bool IsMemoryBased() const {
    return absl::holds_alternative<DataVector<uint8_t>>(data_);
  }
  bool HasFilter() const;

 private:
  friend class CPDF_Dictionary;

  // Initializes with empty data and /Length set to 0 in `dict`.
  // `dict` must be non-null and be a direct object.
  explicit CPDF_Stream(RetainPtr<CPDF_Dictionary> dict);

  // Copies `span` and `stream`, respectively. Creates a new dictionary with the
  // /Length set.
  explicit CPDF_Stream(pdfium::span<const uint8_t> span);
  explicit CPDF_Stream(fxcrt::ostringstream* stream);

  // Reads data from `file`. `dict` will have its /Length set based on `file`.
  // `dict` must be non-null and be a direct object.
  CPDF_Stream(RetainPtr<IFX_SeekableReadStream> file,
              RetainPtr<CPDF_Dictionary> dict);

  // Takes `data`.
  // `dict` must be non-null and be a direct object.
  CPDF_Stream(DataVector<uint8_t> data, RetainPtr<CPDF_Dictionary> dict);
  ~CPDF_Stream() override;

  const CPDF_Dictionary* GetDictInternal() const override;
  RetainPtr<CPDF_Object> CloneNonCyclic(
      bool bDirect,
      std::set<const CPDF_Object*>* pVisited) const override;

  void SetLengthInDict(int length);

  absl::variant<RetainPtr<IFX_SeekableReadStream>, DataVector<uint8_t>> data_;
  RetainPtr<CPDF_Dictionary> dict_;
};

inline CPDF_Stream* ToStream(CPDF_Object* obj) {
  return obj ? obj->AsMutableStream() : nullptr;
}

inline const CPDF_Stream* ToStream(const CPDF_Object* obj) {
  return obj ? obj->AsStream() : nullptr;
}

inline RetainPtr<CPDF_Stream> ToStream(RetainPtr<CPDF_Object> obj) {
  return RetainPtr<CPDF_Stream>(ToStream(obj.Get()));
}

inline RetainPtr<const CPDF_Stream> ToStream(RetainPtr<const CPDF_Object> obj) {
  return RetainPtr<const CPDF_Stream>(ToStream(obj.Get()));
}

#endif  // CORE_FPDFAPI_PARSER_CPDF_STREAM_H_
`CPDF_Stream` 类是 `CPDF_Object` 的一个具体实现，用于表示 PDF 文档中的流对象。以下是它提供的接口功能：

### 类 `CPDF_Stream`

#### 静态常量
1. * *kFileBufSize * *：文件缓冲区大小，值为 512。

#### 构造函数（通过工厂模式）
2. * *CONSTRUCT_VIA_MAKE_RETAIN * *：使用 `MakeRetain` 方式构造。

#### 重载的 `CPDF_Object` 方法
3. * *Type GetType() const override * *：
- 获取对象的类型。

4. * *RetainPtr<CPDF_Object> Clone() const override * *：
- 克隆流对象。

5. * *WideString GetUnicodeText() const override * *：
- 获取流对象的 Unicode 文本表示。

6. * *CPDF_Stream * AsMutableStream() override * *：
- 返回流对象的可变指针。

7. * *bool WriteTo(IFX_ArchiveStream * archive, const CPDF_Encryptor * encryptor) const override * *：
- 将流对象写入到档案流。

#### 主要方法
8. * *size_t GetRawSize() const** ：
- 获取原始数据的大小。

9. * *pdfium::span<const uint8_t> GetInMemoryRawData() const** ：
- 获取内存中的原始数据。

10. * *void SetData(pdfium::span<const uint8_t> pData) * *：
- 设置流数据。

11. * *void SetDataFromStringstream(fxcrt::ostringstream * stream) * *：
- 从字符串流设置数据。

12. * *void TakeData(DataVector<uint8_t> data) * *：
- 接收数据为内部所有。

13. * *void SetDataAndRemoveFilter(pdfium::span<const uint8_t> pData) * *：
- 设置数据并移除 "Filter" 和 "DecodeParms" 字段。

14. * *void SetDataFromStringstreamAndRemoveFilter(fxcrt::ostringstream * stream) * *：
- 从字符串流设置数据并移除 "Filter" 和 "DecodeParms" 字段。

15. * *void InitStreamFromFile(RetainPtr<IFX_SeekableReadStream> file) * *：
- 从文件初始化流。

16. * *DataVector<uint8_t> ReadAllRawData() const** ：
- 读取所有原始数据，仅适用于非内存流。

17. * *bool IsFileBased() const** ：
- 检查流是否基于文件。

18. * *bool IsMemoryBased() const** ：
- 检查流是否基于内存。

19. * *bool HasFilter() const** ：
- 检查流是否具有过滤器。

#### 私有成员函数
20. * *const CPDF_Dictionary * GetDictInternal() const override * *：
- 获取内部字典对象。

21. * *RetainPtr<CPDF_Object> CloneNonCyclic(bool bDirect, std::set<const CPDF_Object*>*pVisited) const override * *：
- 克隆对象，避免循环引用。

22. * *void SetLengthInDict(int length) * *：
- 设置字典中的长度值。

#### 辅助函数
23. * *inline CPDF_Stream * ToStream(CPDF_Object * obj) * *：
- 将 `CPDF_Object` 指针转换为 `CPDF_Stream` 可变指针。

24. * *inline const CPDF_Stream * ToStream(const CPDF_Object * obj) * *：
- 将 `CPDF_Object` 常量指针转换为 `CPDF_Stream` 常量指针。

25. * *inline RetainPtr<CPDF_Stream> ToStream(RetainPtr<CPDF_Object> obj) * *：
- 将 `RetainPtr<CPDF_Object > ` 转换为 `RetainPtr<CPDF_Stream > ` 指针。

26. * *inline RetainPtr<const CPDF_Stream> ToStream(RetainPtr<const CPDF_Object> obj) * *：
- 将 `RetainPtr<const CPDF_Object > ` 转换为 `RetainPtr<const CPDF_Stream > ` 指针。

这些接口和方法提供了管理和操作 PDF 流对象的功能，包括支持从内存或文件读取和写入数据。